/*
 * Copyright (C), 2002-2016, 苏宁易购电子商务有限公司
 * FileName: DeploymentApi.java
 * Author:   admin
 * Date:     2016年1月4日 下午2:46:27
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.suning.app.snpaasadmin.api;

import com.suning.app.snpaasadmin.domain.OauthToken;
import com.suning.app.snpaasadmin.exception.BoshException;
import com.suning.app.snpaasadmin.pojo.CfClusterConfig;
import com.suning.app.snpaasadmin.pojo.CfMysqlClusterConfig;
import com.suning.app.snpaasadmin.util.CloudFoundryClientUtil;
import com.suning.app.snpaasadmin.util.Constants;
import com.suning.app.snpaasadmin.util.HttpClientResponse;
import com.suning.app.snpaasadmin.util.HttpClientUtil;
import com.suning.app.snpaasadmin.util.HttpStatusUtil;
import com.suning.app.snpaasadmin.util.JsonUtil;
import com.suning.app.snpaasadmin.util.StringUtil;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletContext;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.yaml.snakeyaml.Yaml;

/**
 * 〈一句话功能简述〉<br>
 * 〈功能详细描述〉
 *
 * @author admin
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public class DeploymentApi {

    public static List<Map<String, Object>> getDeployments(HttpContext httpContext, HttpHost httpHost , Logger logger)
            throws Exception {
        String urlPath = httpHost.toString() + "/deployments";
        HttpClientResponse response = HttpClientUtil.doGet(urlPath, null, null, httpHost, httpContext);
        if (!HttpStatusUtil.isSuccessStatus(response.getStatus())) {
            String content = response.getBody();
            Map<String, Object> data = JsonUtil.convertJsonToMap(content);
            throw new BoshException(String.valueOf(response.getStatus()), data.get("description").toString());
        }
        String content = response.getBody();
        return JsonUtil.convertJsonToList(content);
    }

    public static boolean getClusterState(HttpContext httpContext, HttpHost httpHost, Integer taskId) throws Exception {
        String urlPath = httpHost.toString() + "/tasks/" + taskId + "/output?type=result";
        HttpClientResponse response = HttpClientUtil.doGet(urlPath, null, null, httpHost, httpContext);
        if (!HttpStatusUtil.isSuccessStatus(response.getStatus())) {
            String content = response.getBody();
            Map<String, Object> data = JsonUtil.convertJsonToMap(content);
            throw new BoshException(String.valueOf(response.getStatus()), data.get("description").toString());
        }
        String content = response.getBody();
        if (StringUtil.isEmpty(content)) {
            return false;
        }
        String[] results = content.split("\n");
        for (int i = 0; i < results.length; i++) {
            Map<String, Object> res = JsonUtil.convertJsonToMap(results[i]);
            if (!"running".equals(res.get("job_state").toString())) {
                return false;
            }
        }
        return true;
    }

    public static String generateyml(Map<String, Object> input, Integer flag, Logger logger , ServletContext servletContext) throws Exception {
        String random = UUID.randomUUID().toString();
        String path = "";
        if (flag == Constants.MYSQL_CLUSTER) {
            path = servletContext.getRealPath("/WEB-INF/classes/cf-mysql-python-prd.yml");
            logger.fatal("源文件地址："+path);
            String pyPath = servletContext.getRealPath("/WEB-INF/classes/playpython.py");
            logger.fatal("python源文件地址："+pyPath);
            readMysqlFile(path, "/opt/logs/"+ random + ".yml", input);
            String commod = "python " + pyPath + " " + "/opt/logs/"+ random + ".yml";
            Process pro = Runtime.getRuntime()
                    .exec(commod);
            pro.waitFor();
            return "/opt/logs/"+ random + ".yml";
        } else {
            path = servletContext.getRealPath("/WEB-INF/classes/cf222-python-prd.yml");
            String pyPath = servletContext.getRealPath("/WEB-INF/classes/playpython.py");
            readFile(path, "/opt/logs/"+random + ".yml", input);
            Process pro = Runtime.getRuntime()
                    .exec("python " + pyPath.substring(1) + " " + "/opt/logs/" + random + ".yml");
            pro.waitFor();
            return "/opt/logs/" + random + ".yml";
        }
    }

    @SuppressWarnings("unchecked")
    public static String getyml(String path) throws Exception {
        Yaml yaml = new Yaml();
        File file = new File(path);
        InputStream in = null;
        Map<String, Object> list = new HashMap<>();
        try {
            in = new FileInputStream(file);
            list = (Map<String, Object>) yaml.load(in);
        } catch (Exception e) {
            throw e;
        } finally {
            in.close();
            if (file != null) {
                file.delete();
            }
        }
        return yaml.dump(list);
    }

    public static void readFile(String filePath, String savePath, Map<String, Object> input) throws Exception {
        String content = "";
        BufferedWriter bw = null;
        try {
            Path path = FileSystems.getDefault().getPath(filePath);
            byte[] b = Files.readAllBytes(path);
            content = new String(b);
            bw = new BufferedWriter(new FileWriter(savePath));
            String[] args = { "director_uuid", "protocol", "cf_release", "deployment_name", "imageRef", "key_id",
                    "root_domain", "component_domain", "runningtime_domain", "network_id", "sdfs_address" };
            for (String name : args) {
                content = content.replace(name + " = \"\"", name + " = " + "\"" + (String) input.get(name) + "\"");
            }
            String[] components = { "nats", "consul", "postgres", "etcd", "ccng", "hm9000", "dea", "router", "haproxy",
                    "uaa", "doppler", "loggregator_trafficcontroller" };
            for (String component : components) {
                content = content
                        .replace(component + "_size" + " = \"\"",
                                component + "_size" + " = " + ((CfClusterConfig) input.get(component)).getCount())
                        .replace(component + "_cpu_overload" + " = \"\"",
                                component + "_cpu_overload" + " = "
                                        +  "\""+((CfClusterConfig) input.get(component)).getCpuOverload().toString() +"\"")
                        .replace(component + "_cpu_number" + " = \"\"",
                                component + "_cpu_number" + " = "
                                        + ((CfClusterConfig) input.get(component)).getCpuCore())
                        .replace(component + "_memory_size" + " = \"\"",
                                component + "_memory_size" + " = "
                                        + ((CfClusterConfig) input.get(component)).getMemorySize())
                        .replace(component + "_net_id" + " = \"\"", component + "_net_id" + " = " + "\""
                                + ((CfClusterConfig) input.get(component)).getNetId() + "\"");
            }
            bw.write(content);
            bw.flush();
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (bw != null)
                    bw.close();
            } catch (Exception e) {
                throw e;
            }
        }
    }

    private static String getTaskStatus(HttpContext httpContext, HttpHost httpHost, String taskId) throws Exception {
        String urlPath = httpHost.toString() + "/tasks/" + taskId;
        HttpClientResponse response = HttpClientUtil.doGet(urlPath, null, null, httpHost, httpContext);
        if (!HttpStatusUtil.isSuccessStatus(response.getStatus())) {
            String content = response.getBody();
            Map<String, Object> data = JsonUtil.convertJsonToMap(content);
            throw new BoshException(String.valueOf(response.getStatus()), data.get("description").toString());
        }
        String body = response.getBody();
        Map<String, Object> info = JsonUtil.convertJsonToMap(body);
        return (String) info.get("state");
    }

    public static String deployCluster(HttpContext httpContext, HttpHost httpHost, String data) throws Exception {
        String urlPath = httpHost.toString() + "/deployments";
        CloseableHttpResponse response = HttpClientUtil.doPostWithBodyData(urlPath, data, httpHost, httpContext);
        String location = "";
        try {
            if (response.getStatusLine().getStatusCode() == Constants.HTTP_302) {
                Header locationHeader = response.getFirstHeader("Location");
                if (locationHeader != null) {
                    location = locationHeader.getValue();
                    location = location.substring(location.lastIndexOf("/") + 1, location.length());
                }
            }
            if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
                HttpEntity resentity = response.getEntity();
                String content = null;
                if (resentity != null) {
                    content = EntityUtils.toString(resentity, "UTF-8");
                }
                Map<String, Object> res = JsonUtil.convertJsonToMap(content);
                throw new BoshException(String.valueOf(response.getStatusLine().getStatusCode()),
                        res.get("description").toString());
            }
        } catch (Exception e) {
            throw e;
        }
        return location;
    }

    public static void readMysqlFile(String filePath, String savePath, Map<String, Object> input) throws Exception {
        String content = "";
        BufferedWriter bw = null;
        String plan_id = UUID.randomUUID().toString();
        String broker_id = UUID.randomUUID().toString();
        input.put("plan_id", plan_id);
        input.put("broker_id", broker_id);
        input.put("connections", "500");
        try {
            Path path = FileSystems.getDefault().getPath(filePath);
            byte[] b = Files.readAllBytes(path);
            content = new String(b);
            bw = new BufferedWriter(new FileWriter(savePath));
            String[] args = { "director_uuid", "cf_deployment_name", "deployment_name", "cf_mysql", "root_domain",
                    "component_domain", "network_id", "plan_id", "broker_id" };
            for (String name : args) {
                content = content.replace(name + " = \"\"", name + " = " + "\"" + (String) input.get(name) + "\"");
            }
            String[] argsInt = { "nats_size", "storage_mb", "connections" };
            for (String name : argsInt) {
                content = content.replace(name + " = \"\"", name + " = " + input.get(name));
            }
            String[] components = { "mysql" };
            for (String component : components) {
                content = content
                        .replace(component + "_cpu_overload" + " = \"\"",
                                component + "_cpu_overload" + " = "
                                        + "\""+((CfMysqlClusterConfig) input.get(component)).getCpuOverload().toString()+"\"")
                        .replace(component + "_cpu_number" + " = \"\"",
                                component + "_cpu_number" + " = "
                                        + ((CfMysqlClusterConfig) input.get(component)).getCpuCore())
                        .replace(component + "_memory_size" + " = \"\"", component + "_memory_size" + " = "
                                + ((CfMysqlClusterConfig) input.get(component)).getMemorySize());
            }

            bw.write(content);
            bw.flush();
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (bw != null) {
                    bw.close();
                }
            } catch (Exception e) {
                throw e;
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static String createServiceBroker(String domain, Map<String, String> params) throws Exception {
        String cfUrl = "http://api." + domain + "/v2/service_brokers";
        OauthToken token = OauthApi.login(Constants.BROKER_AUTH_USERNAME, Constants.BROKER_AUTH_PASSWORD, domain);
        String content = CloudFoundryClientUtil.doCCPost(cfUrl, params, token);
        Map<String, Object> res = JsonUtil.convertJsonToMap(content);
        String brokerGuid = ((Map<String, Object>) res.get("metadata")).get("guid").toString();
        String serviceGuid = getServiceUuid(brokerGuid, domain, token);
        String planId = getPlanUuid(domain, serviceGuid, token);
        if (!setPlanVisibility(domain, planId, token)) {
            return null;
        }
        return brokerGuid;
    }

    /**
     * 
     * 功能描述: <br>
     * service_plan public to true
     *
     * @param domain
     * @param planId
     * @return
     * @throws Exception
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static boolean setPlanVisibility(String domain, String planId, OauthToken token) throws Exception {
        Map<String, Object> params = new HashMap<String, Object>();
        String urlPath = "http://api." + domain + "/v2/service_plans/" + planId;
        params.put("public", true);
        CloudFoundryClientUtil.doCCPut(urlPath, params, token);
        return true;
    }

    @SuppressWarnings("unchecked")
    public static String getPlanUuid(String domain, String serviceUuid, OauthToken token) throws Exception {
        String planUuid = "";
        String urlPath = "http://api." + domain + "/v2/services/" + serviceUuid + "/service_plans";
        String content = CloudFoundryClientUtil.doCCGet(urlPath, null, token);
        Map<String, Object> data = JsonUtil.convertJsonToMap(content);
        planUuid = (String) ((List<Map<String, Map<String, Object>>>) data.get("resources")).get(0).get("metadata")
                .get("guid");
        return planUuid;
    }

    @SuppressWarnings("unchecked")
    public static String getServiceUuid(String brokerUuid, String domain, OauthToken token) throws Exception {
        String serviceUuid = "";
        String urlPath = "http://api." + domain + "/v2/services?q=service_broker_guid:" + brokerUuid;
        String response = CloudFoundryClientUtil.doCCGet(urlPath, null, token);
        Map<String, Object> data = JsonUtil.convertJsonToMap(response);
        serviceUuid = (String) ((List<Map<String, Map<String, Object>>>) data.get("resources")).get(0).get("metadata")
                .get("guid");
        return serviceUuid;
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> getDeployingLog(String taskId, Integer offset, HttpContext httpContext,
            HttpHost httpHost) throws Exception {
        String logUrlPath = httpHost.toString() + "/tasks/" + taskId + "/output?type=event";
        Map<String, String> header = new HashMap<>();
        String output = "";
        header.put("Range", "bytes=" + offset + "-");
        List<Map<String, Object>> logDeploying = new ArrayList<>();
        while (StringUtil.isEmpty(output) || StringUtil.isBlank(output)) {
            CloseableHttpResponse responseTwo = HttpClientUtil.doGetDeployLog(logUrlPath, null, header, httpHost,
                    httpContext);
            if (responseTwo.getStatusLine().getStatusCode() == Constants.HTTP_206) {
                Header contentHeader = responseTwo.getFirstHeader("Content-Range");
                if (contentHeader != null) {
                    String content = contentHeader.getValue();
                    offset = Integer.valueOf(content.substring(content.indexOf("-") + 1, content.indexOf("/"))) + 1;
                }
                HttpEntity resentity = responseTwo.getEntity();
                if (resentity != null) {
                    output = EntityUtils.toString(resentity, "UTF-8");
                }
            } else if (responseTwo.getStatusLine().getStatusCode() == Constants.HTTP_416) {
                String status = getTaskStatus(httpContext, httpHost, taskId);
                if ("done error cancelled".contains(status)) {
                    Map<String, Object> logRes = new HashMap<>();
                    Map<String, Object> line = new HashMap<>();

                    line.put("message", "task is " + status);
                    if (status.equals("done")) {
                        line.put("flag", 3);
                    } else if (status.equals("error")) {
                        line.put("flag", 4);
                    } else if (status.equals("cancelled")) {
                        line.put("flag", 5);
                    }
                    logDeploying.add(line);
                    logRes.put("log", logDeploying);
                    logRes.put("offset", offset);
                    return logRes;
                } else {
                    output = "";
                    Thread.sleep(5000);
                }
            } else if (!HttpStatusUtil.isSuccessStatus(responseTwo.getStatusLine().getStatusCode())) {
                HttpEntity resentity = responseTwo.getEntity();
                String content = null;
                if (resentity != null) {
                    content = EntityUtils.toString(resentity, "UTF-8");
                }
                Map<String, Object> res = JsonUtil.convertJsonToMap(content);
                throw new BoshException(String.valueOf(responseTwo.getStatusLine().getStatusCode()),
                        res.get("description").toString());
            }
        }

        if (StringUtil.isNotEmpty(output)) {
            String[] reStrings = output.split("\n");
            for (String log : reStrings) {
                Map<String, Object> logInfo = JsonUtil.convertJsonToMap(log);
                String tmp = "";
                Map<String, Object> line = new HashMap<>();
                String tagInfo = "";
                if (logInfo.containsKey("error")) {
                    line.put("flag", 2);
                    tmp = "Error " + ((Map<String, Object>) logInfo.get("error")).get("code") + ": "
                            + ((Map<String, Object>) logInfo.get("error")).get("message");
                } else {
                    List<String> tags = (List<String>) logInfo.get("tags");
                    if (tags != null && tags.size() > 0) {
                        for (String tag : tags) {
                            tagInfo = tagInfo + "," + tag;
                        }
                        tagInfo = tagInfo.substring(0, tagInfo.length() - 1);
                    }
                    tmp = logInfo.get("stage") + " " + tagInfo + " > " + logInfo.get("task") + " "
                            + logInfo.get("state");
                    if (!logInfo.get("state").toString().equals("failed")) {
                        line.put("flag", 1);
                        tmp = tmp + " " + "progress: " + logInfo.get("progress");
                    } else {
                        line.put("flag", 2);
                        tmp = tmp + "\n" + logInfo.get("data");
                    }
                }

                line.put("message", tmp);
                logDeploying.add(line);
            }
        }
        Map<String, Object> logRes = new HashMap<>();
        logRes.put("log", logDeploying);
        logRes.put("offset", offset);
        return logRes;
    }

    public static String downloadDeployLog(String taskId, HttpContext httpContext, HttpHost httpHost) throws Exception {
        String logUrlPath = httpHost.toString() + "/tasks/" + taskId + "/output?type=event";
        Map<String, String> header = new HashMap<>();
        header.put("Range", "bytes=0-");
        String output = "";
        CloseableHttpResponse responseTwo = HttpClientUtil.doGetDeployLog(logUrlPath, null, header, httpHost,
                httpContext);
        if (responseTwo.getStatusLine().getStatusCode() == Constants.HTTP_206) {
            HttpEntity resentity = responseTwo.getEntity();
            if (resentity != null) {
                output = EntityUtils.toString(resentity, "UTF-8");
            }
        }
        if (!HttpStatusUtil.isSuccessStatus(responseTwo.getStatusLine().getStatusCode())) {
            HttpEntity resentity = responseTwo.getEntity();
            String content = null;
            if (resentity != null) {
                content = EntityUtils.toString(resentity, "UTF-8");
            }
            Map<String, Object> res = JsonUtil.convertJsonToMap(content);
            throw new BoshException(String.valueOf(responseTwo.getStatusLine().getStatusCode()),
                    res.get("description").toString());
        }
        return output;
    }

    public static void deleteCfCluster(HttpContext httpContext, HttpHost httpHost, String name) throws Exception {
        String url = httpHost.toString() + "/deployments/" + name;
        HttpClientResponse response = HttpClientUtil.doDelete(url, null, null, httpHost, httpContext);
        if (response.getStatus() != Constants.HTTP_404 && !HttpStatusUtil.isSuccessStatus(response.getStatus())) {
            String content = response.getBody();
            Map<String, Object> data = JsonUtil.convertJsonToMap(content);
            throw new BoshException(String.valueOf(response.getStatus()), data.get("description").toString());
        }
    }

    public static void deleteServiceBroker(String brokerUuid, String domain) throws Exception {
        String cfUrl = "http://api." + domain + "/v2/service_brokers/" + brokerUuid;
        OauthToken token = OauthApi.login(Constants.BROKER_AUTH_USERNAME, Constants.BROKER_AUTH_PASSWORD, domain);
        CloudFoundryClientUtil.doCCDelete(cfUrl, null, token);

    }

    public static void deleteMysqlCluster(HttpContext httpContext, HttpHost httpHost, String name) throws Exception {
        String url = httpHost.toString() + "/deployments/" + name;
        HttpClientResponse response = HttpClientUtil.doDelete(url, null, null, httpHost, httpContext);
        if (response.getStatus() != Constants.HTTP_404 && !HttpStatusUtil.isSuccessStatus(response.getStatus())) {
            String content = response.getBody();
            Map<String, Object> data = JsonUtil.convertJsonToMap(content);
            throw new BoshException(String.valueOf(response.getStatus()), data.get("description").toString());
        }
    }
}
